#include "mainwidget.h"
#include "debug.h"
#include "model/datacenter.h"
#include "toast.h"

// using namespace model;

MainWidget *MainWidget::instance = nullptr;
MainWidget *MainWidget::getInstance()
{
    if (instance == nullptr)
    {
        // 由于此处的窗口是整个函数的主窗口，所以它的父窗口就是桌面，parent设定为nullptr即可
        instance = new MainWidget();
    }
    return instance;
}

MainWidget::MainWidget(QWidget *parent) : QWidget(parent)
{
    this->setWindowTitle("我的聊天室");
    this->setWindowIcon(QIcon(":/resource/image/logo.png"));
    // this->resize(1180, 600);

    // 初始化主窗口的样式布局
    initMainWindow();
    // 初始化左侧窗口布局
    initLeftWindow();
    // 初始化中间窗口布局
    initMidWindow();
    // 初始化右侧窗口布局
    initRightWindow();
    // 初始化信号槽
    initSignalSlot();

    initWebsocket();
}

MainWidget::~MainWidget() {}

void MainWidget::initMainWindow()
{
    QHBoxLayout *layout = new QHBoxLayout();
    // 设置内部元素之间的间隔为0
    layout->setSpacing(0);
    // 设置layout中的元素四个方向紧贴边缘
    layout->setContentsMargins(0, 0, 0, 0);
    this->setLayout(layout);

    _windowLeft  = new QWidget();
    _windowMid   = new QWidget();
    _windowRight = new QWidget();

    _windowLeft->setFixedWidth(70);
    _windowMid->setFixedWidth(310);
    _windowRight->setMinimumWidth(800);

    _windowLeft->setStyleSheet("QWidget {background-color: rgb(46,46,46);}");
    _windowMid->setStyleSheet("QWidget {background-color: rgb(247,247,247);}");
    _windowRight->setStyleSheet("QWidget {background-color: rgb(245,245,245);}");

    layout->addWidget(_windowLeft);
    layout->addWidget(_windowMid);
    layout->addWidget(_windowRight);
}

void MainWidget::initLeftWindow()
{
    QVBoxLayout *layout = new QVBoxLayout();
    layout->setSpacing(20);
    layout->setContentsMargins(0, 50, 0, 0);
    _windowLeft->setLayout(layout);

    // 添加用户头像
    _userAvatar = new QPushButton();
    _userAvatar->setFixedSize(45, 45);
    _userAvatar->setIconSize(QSize(45, 45));
    _userAvatar->setIcon(QIcon(":/resource/image/defaultAvatar.png"));
    _userAvatar->setStyleSheet("QPushButton {background-color: transparent;}");
    layout->addWidget(_userAvatar, 1, Qt::AlignTop | Qt::AlignHCenter);

    // 添加会话标签页按钮
    _sessionTabBtn = new QPushButton();
    _sessionTabBtn->setFixedSize(45, 45);
    _sessionTabBtn->setIconSize(QSize(30, 30));
    _sessionTabBtn->setIcon(QIcon(":/resource/image/session_active.png"));
    _sessionTabBtn->setStyleSheet("QPushButton {background-color: transparent;}");
    layout->addWidget(_sessionTabBtn, 1, Qt::AlignTop | Qt::AlignHCenter);

    // 添加好友标签页按钮
    _friendTabBtn = new QPushButton();
    _friendTabBtn->setFixedSize(45, 45);
    _friendTabBtn->setIconSize(QSize(30, 30));
    _friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
    _friendTabBtn->setStyleSheet("QPushButton {background-color: transparent;}");
    layout->addWidget(_friendTabBtn, 1, Qt::AlignTop | Qt::AlignHCenter);

    // 添加好友标签页按钮
    _applyTabBtn = new QPushButton();
    _applyTabBtn->setFixedSize(45, 45);
    _applyTabBtn->setIconSize(QSize(30, 30));
    _applyTabBtn->setIcon(QIcon(":/resource/image/appky_inactive.png"));
    _applyTabBtn->setStyleSheet("QPushButton {background-color: transparent;}");
    layout->addWidget(_friendTabBtn, 1, Qt::AlignTop | Qt::AlignHCenter);

    layout->addStretch(20);
}

void MainWidget::initMidWindow()
{
    QGridLayout *layout = new QGridLayout();
    layout->setContentsMargins(0, 20, 0, 0);
    layout->setHorizontalSpacing(0);
    layout->setVerticalSpacing(10);
    _windowMid->setLayout(layout);

    _searchEdit = new QLineEdit();
    // 固定搜索栏缩放大小
    _searchEdit->setFixedHeight(30);
    _searchEdit->setPlaceholderText("搜索");
    _searchEdit->setStyleSheet("QLienEdit { border-radius: 5px,backgroud-color: rgb(226,226,226);padding-left: 5px;}");

    _addFriendBtn = new QPushButton();
    _addFriendBtn->setFixedSize(30, 30);
    _addFriendBtn->setIcon(QIcon(":/resource/image/cross.png"));
    QString style = "QPushButton { border-radius: 5px,backgroud-color: rgb(226,226,226);}";
    style += "QPushButton::pressed {background-color: rgv(240,240,240);}";
    _addFriendBtn->setStyleSheet(style);

    _sessionFriendArea = new SessionFriendArea();

    // 创建空白的 Widget 填充到布局管理器中
    QWidget *spacer1 = new QWidget();
    spacer1->setFixedWidth(10);
    QWidget *spacer2 = new QWidget();
    spacer2->setFixedWidth(10);
    QWidget *spacer3 = new QWidget();
    spacer3->setFixedWidth(10);

    layout->addWidget(spacer1, 0, 0);
    layout->addWidget(_searchEdit, 0, 1);
    layout->addWidget(spacer2, 0, 2);
    layout->addWidget(_addFriendBtn, 0, 3);
    layout->addWidget(spacer3, 0, 4);
    layout->addWidget(_sessionFriendArea, 1, 0, 1, 5); // 表示在第 1 行第 0 列中占用 1 行 5 列个位置
}

void MainWidget::initRightWindow()
{
    // 1. 创建右侧窗口的布局管理器
    QVBoxLayout *vlayout = new QVBoxLayout();
    vlayout->setSpacing(0);
    vlayout->setContentsMargins(0, 0, 0, 0);
    vlayout->setAlignment(Qt::AlignTop);
    _windowRight->setLayout(vlayout);

    // 2. 创建上方标题栏
    QWidget *titleWidget = new QWidget();
    titleWidget->setFixedHeight(62);
    titleWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    titleWidget->setObjectName("titleWidget");
    titleWidget->setStyleSheet(
        "#titleWidget { border-bottom: 1px solid rgb(230, 230, 230); border-left: 1px solid rgb(230, 230, 230); }");
    vlayout->addWidget(titleWidget);

    // 3. 给标题栏添加标题 label 和一个 按钮
    QHBoxLayout *hlayout = new QHBoxLayout();
    hlayout->setSpacing(0);
    // 使标题的 label 和 按钮 距离左右两侧的边界有点间隔
    hlayout->setContentsMargins(10, 0, 10, 0);
    titleWidget->setLayout(hlayout);

    _sessionTitleLabel = new QLabel();
    _sessionTitleLabel->setStyleSheet("QLabel { font-size: 22px; border-bottom: 1px solid rgb(230, 230, 230);}");
#if TEST_UI
    _sessionTitleLabel->setText("这是会话标题");
#endif
    hlayout->addWidget(_sessionTitleLabel);

    _extraBtn = new QPushButton();
    _extraBtn->setFixedSize(30, 30);
    _extraBtn->setIconSize(QSize(30, 30));
    _extraBtn->setIcon(QIcon(":/resource/image/more.png"));
    _extraBtn->setStyleSheet("QPushButton { border:none; background-color: rgb(245, 245, 245); } QPushButton:pressed { "
                             "background-color: rgb(220, 220, 220); }");
    hlayout->addWidget(_extraBtn);

    // 4. 添加消息展示区
    _messageShowArea = new MessageShowArea();
    vlayout->addWidget(_messageShowArea);

    // 5. 添加消息编辑区
    _messageEditArea = new MessageEditArea();
    vlayout->addWidget(_messageEditArea, 0, Qt::AlignBottom);
}

void MainWidget::initSignalSlot()
{
    model::DataCenter *dataCenter = model::DataCenter::getInstance();

    /////////////////////////////////////////////
    ////连接信号槽, 处理标签页按钮切换的问题
    /////////////////////////////////////////////
    connect(_sessionTabBtn, &QPushButton::clicked, this, &MainWidget::switchTabToSession);
    connect(_friendTabBtn, &QPushButton::clicked, this, &MainWidget::switchTabToFriend);
    connect(_applyTabBtn, &QPushButton::clicked, this, &MainWidget::switchTabToApply);

    /////////////////////////////////////////////
    /// 点击自己的头像, 弹出对话框显示个人主页
    /////////////////////////////////////////////
    connect(_userAvatar, &QPushButton::clicked, this,
            [=]()
            {
                SelfInfoWidget *selftInfoWidget = new SelfInfoWidget(this);
                selftInfoWidget->exec();
            });

    /////////////////////////////////////////////
    /// 点击会话详情按钮, 弹出会话详情窗口
    /////////////////////////////////////////////
    connect(_extraBtn, &QPushButton::clicked, this,
            [=]()
            {
                bool isSingleChat = false;
                if (isSingleChat)
                {
                    SessionDetailWidget *sessionDetailWidget = new SessionDetailWidget(this, model::UserInfo());
                    sessionDetailWidget->show();
                }
                else
                {
                    GroupSessionDetailWidget *groupSessionDetailWidget = new GroupSessionDetailWidget(this);
                    groupSessionDetailWidget->show();
                }
            });

    /////////////////////////////////////////////
    /// 点击添加好友按钮, 弹出添加好友窗口
    /////////////////////////////////////////////
    connect(_addFriendBtn, &QPushButton::clicked, this,
            [=]()
            {
                AddFriendDialog *addFriendDialog = new AddFriendDialog(this);
                addFriendDialog->exec();
            });

    /////////////////////////////////////////////
    /// 修改搜索框内容, 弹出添加好友对话框
    /////////////////////////////////////////////
    connect(_searchEdit, &QLineEdit::textEdited, this,
            [=]()
            {
                // 取出当前输入框的内容，设置到新弹出的输入框里
                const QString &searchKey         = _searchEdit->text();
                AddFriendDialog *addFriendDialog = new AddFriendDialog(this);
                addFriendDialog->setSearchKey(searchKey);
                // 清空主窗口的文本内容
                _searchEdit->setText("");
                addFriendDialog->exec();
            });

    /////////////////////////////////////////////
    /// 获取个人信息
    /////////////////////////////////////////////
    connect(dataCenter, &model::DataCenter::getMyselfDone, this,
            [=]()
            {
                auto myself = dataCenter->getMyself();
                _userAvatar->setIcon(myself->avatar);
            });
    dataCenter->getMyselfAsync();

    /////////////////////////////////////////////
    /// 获取好友列表
    /////////////////////////////////////////////
    loadFriendList();

    /////////////////////////////////////////////
    /// 获取会话列表
    /////////////////////////////////////////////
    loadSessionList();

    /////////////////////////////////////////////
    /// 获取好友申请列表
    /////////////////////////////////////////////
    loadApplyList();

    /////////////////////////////////////////////
    /// 处理修改头像
    /////////////////////////////////////////////
    connect(dataCenter, &model::DataCenter::changeAvatarDone, this,
            [=]()
            {
                model::UserInfo *myself = dataCenter->getMyself();
                _userAvatar->setIcon(myself->avatar);
            });

    /////////////////////////////////////////////
    /// 处理删除好友
    /////////////////////////////////////////////
    connect(dataCenter, &model::DataCenter::deleteFriendDone, this,
            [=]()
            {
                // 更新会话列表和好友列表
                this->updateFriendList();
                this->updateChatSessionList();
                LOG() << "删除好友完成";
            });

    connect(dataCenter, &model::DataCenter::clearCurrentSession, this,
            [=]()
            {
                _sessionTitleLabel->setText("");
                _messageShowArea->clear();
                dataCenter->setCurrentChatSessionId("");
                LOG() << "清空当前会话完成";
            });

    /////////////////////////////////////////////
    /// 处理添加好友申请
    /////////////////////////////////////////////
    connect(dataCenter, &model::DataCenter::addFriendApplyDone, this, [=]() { Toast::showMessage("好友申请已发送"); });

    /////////////////////////////////////////////
    /// 处理添加好友申请推送数据
    /////////////////////////////////////////////
    connect(dataCenter, &model::DataCenter::receiveFriendApplyDone, this,
            [=]()
            {
                this->updateApplyList();
                Toast::showMessage("收到新的好友申请");
            });
}

void MainWidget::initWebsocket()
{
    model::DataCenter *dataCenter = model::DataCenter::getInstance();
    dataCenter->initWebsocket();
}

void MainWidget::switchTabToSession()
{
    // 1. 记录当前切换到了哪个标签页
    _activeTab = SESSION_LIST;

    // 2. 调整图标显示情况，把选中的图标换成active，其他换成inactive
    _sessionTabBtn->setIcon(QIcon(":/resource/image/session_active.png"));
    _friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
    _applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));

    // 3. 在主窗口的中间部分，加载出会话列表内容
    this->loadSessionList();
}

void MainWidget::switchTabToFriend()
{
    // 1. 记录当前切换到了哪个标签页
    _activeTab = FRIEND_LIST;

    // 2. 调整图标显示情况，把选中的图标换成active，其他换成inactive
    _sessionTabBtn->setIcon(QIcon(":/resource/image/session_inactive.png"));
    _friendTabBtn->setIcon(QIcon(":/resource/image/friend_active.png"));
    _applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));

    // 3. 在主窗口的中间部分，加载出会话列表内容
    this->loadFriendList();
}

void MainWidget::switchTabToApply()
{
    // 1. 记录当前切换到了哪个标签页
    _activeTab = APPLY_LIST;

    // 2. 调整图标显示情况，把选中的图标换成active，其他换成inactive
    _sessionTabBtn->setIcon(QIcon(":/resource/image/session_inactive.png"));
    _friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
    _applyTabBtn->setIcon(QIcon(":/resource/image/apply_active.png"));

    // 3. 在主窗口的中间部分，加载出会话列表内容
    this->loadApplyList();
}

void MainWidget::switchSession(const QString &userId)
{
    // 1. 在会话列表中，先找到对应的会话元素
    model::DataCenter *dataCenter           = model::DataCenter::getInstance();
    model::ChatSessionInfo *chatSessionInfo = dataCenter->findChatSessionByUserId(userId);
    if (chatSessionInfo == nullptr)
    {
        // 正常即使好友之间没有说过话，也会有一个对应的会话
        LOG() << "[严重错误] 当前选中的好友，对应的会话不存在！";
        return;
    }
    // 2. 把选中的会话置顶
    dataCenter->topChatSessionInfo(*chatSessionInfo);

    // 3. 切换到会话列表标签页
    switchTabToSession();

    // 4. 加载这个会话对应的历史消息，置顶后该会话的下标为 0
    _sessionFriendArea->clickItem(0);
}

void MainWidget::updateChatSessionList()
{
    if (_activeTab != SESSION_LIST)
    {
        // 当标签页不是会话列表时，不进行任何数据渲染到界面上
        return;
    }
    model::DataCenter *dataCenter                  = model::DataCenter::getInstance();
    QList<model::ChatSessionInfo> *chatSessionList = dataCenter->getChatSessionList();

    _sessionFriendArea->clear();

    for (const auto &c : *chatSessionList)
    {
        if (c.lastMessage.messageType == model::TEXT_TYPE)
        {
            _sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionName,
                                        c.lastMessage.content);
        }
        else if (c.lastMessage.messageType == model::IMAGE_TYPE)
        {
            _sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionName, "[图片]");
        }
        else if (c.lastMessage.messageType == model::FILE_TYPE)
        {
            _sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionName, "[文件]");
        }
        else if (c.lastMessage.messageType == model::SPEECH_TYPE)
        {
            _sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionName, "[语音]");
        }
        else
        {
            LOG() << "错误的消息类型！messageType=" << c.lastMessage.messageType;
        }
    }
}

void MainWidget::loadSessionList()
{
    // 先判断会话列表数据是否在本地（DataCenter）中存在，如果本地存在，直接构造界面内容
    model::DataCenter *dataCenter = model::DataCenter::getInstance();
    if (dataCenter->getChatSessionList() != nullptr)
    {
        // 从内存加载数据显示
        updateChatSessionList();
    }
    else
    {
        // 如果本地不存在，则从服务器获取数据
        // 从网络加载数据显示
        connect(dataCenter, &model::DataCenter::getChatSessionListDone, this, &MainWidget::updateChatSessionList,
                Qt::UniqueConnection);
        dataCenter->getChatSessionListAsync();
    }
}

void MainWidget::loadFriendList()
{
    // 先判断会话列表数据是否在本地（DataCenter）中存在，如果本地存在，直接构造界面内容
    model::DataCenter *dataCenter = model::DataCenter::getInstance();
    if (dataCenter->getFriendList() != nullptr)
    {
        // 从内存加载数据显示
        updateFriendList();
    }
    else
    {
        // 如果本地不存在，则从服务器获取数据
        // 从网络加载数据显示
        connect(dataCenter, &model::DataCenter::getFriendListDone, this, &MainWidget::updateFriendList,
                Qt::UniqueConnection);
        dataCenter->getFriendListAsync();
    }
}

void MainWidget::updateFriendList()
{
    if (_activeTab != FRIEND_LIST)
    {
        // 当标签页不是好友列表时，不进行任何数据渲染到界面上
        return;
    }
    model::DataCenter *dataCenter      = model::DataCenter::getInstance();
    QList<model::UserInfo> *friendList = dataCenter->getFriendList();

    // 清空之前在界面上的数据
    _sessionFriendArea->clear();

    // 遍历好友列表，添加到界面上
    for (const auto &f : *friendList)
    {
        _sessionFriendArea->addItem(FriendItemType, f.userId, f.avatar, f.nickname, f.description);
    }
}

void MainWidget::loadApplyList()
{
    // 先判断会话列表数据是否在本地（DataCenter）中存在，如果本地存在，直接构造界面内容
    model::DataCenter *dataCenter = model::DataCenter::getInstance();
    if (dataCenter->getApplyList() != nullptr)
    {
        // 从内存加载数据显示
        updateApplyList();
    }
    else
    {
        // 如果本地不存在，则从服务器获取数据
        // 从网络加载数据显示
        connect(dataCenter, &model::DataCenter::getApplyListDone, this, &MainWidget::updateApplyList,
                Qt::UniqueConnection);
        dataCenter->getApplyListAsync();
    }
}

void MainWidget::updateApplyList()
{
    if (_activeTab != APPLY_LIST)
    {
        // 当标签页不是好友申请列表时，不进行任何数据渲染到界面上
        return;
    }
    model::DataCenter *dataCenter     = model::DataCenter::getInstance();
    QList<model::UserInfo> *applyList = dataCenter->getApplyList();

    _sessionFriendArea->clear();

    for (const auto &u : *applyList)
    {
        // 直接把 UserInfo 添加到界面上即可
        //  好友申请列表不需要显示个性签名，所以此处的 description 不需要填写
        _sessionFriendArea->addItem(ApplyItemType, u.userId, u.avatar, u.nickname, "");
    }
}

void MainWidget::loadRecentMessage(const QString &chatSessionId)
{
    // 先判定，本地内存中是否已经有对应的消息列表数据
    model::DataCenter *dataCenter = model::DataCenter::getInstance();
    // 如果有直接显示到界面上
    if (dataCenter->getRecentMessageList(chatSessionId) != nullptr)
    {
        // 使用本地数据更新界面
        updateRecentMessage(chatSessionId);
    }
    else
    {
        // 本地没有数据，从网络服务器加载
        connect(dataCenter, &model::DataCenter::getRecentMessageListDone, this, &MainWidget::updateRecentMessage,
                Qt::UniqueConnection);
        dataCenter->getRecentMessageListAsync(chatSessionId, true);
    }
}

void MainWidget::updateRecentMessage(const QString &chatSessionId)
{
    // 1. 拿到该会话的最近消息列表
    model::DataCenter *dataCenter = model::DataCenter::getInstance();
    auto *recentMessageList       = dataCenter->getRecentMessageList(chatSessionId);

    // 2. 清空原有界面上显示的消息列表
    _messageShowArea->clear();

    // 3. 根据当前拿到的消息列表，显示到界面上
    // 用户最先看到的消息是 “最近” 消息，即 “末尾” 的消息，所以使用头插
    for (int i = recentMessageList->size() - 1; i >= 0; i--)
    {
        const Message &message = recentMessageList->at(i);
        bool isLeft            = message.sender.userId != dataCenter->getMyself()->userId;
        _messageShowArea->addFrontMessage(isLeft, message);
    }

    // 4. 设置会话标题
    model::ChatSessionInfo *chatSessionInfo = dataCenter->findChatSessionById(chatSessionId);
    if (chatSessionInfo != nullptr)
    {
        // 把会话名称显示到界面上
        _sessionTitleLabel->setText(chatSessionInfo->chatSessionName);
    }

    // 5. 保存当前选中的会话
    dataCenter->setCurrentChatSessionId(chatSessionId);

    // 6. 自动把滚动条滚动到末尾
    _messageShowArea->scrollToEnd();
}

MessageShowArea *MainWidget::getMessageShowArea() { return _messageShowArea; }
